Начнем рассмотрение с реализации сервера, находящейся в файле ChatServer. h. В архитектуре событий .NET используются делегаты с особой сигнатурой:
_delegate void JoinHandler(
Object *pSender, ChatEventArg *pe);
_delegate void QuitHandler(
Object *pSender, ChatEventArg *pe);
Первый параметр определяет объект, посылающий сообщение о событии. Второй параметр используется для передачи данных одновременно с сообщением о событии. Обычно для хранения таких данных используется класс, производный от EventArg.
_gc class ChatEventArg : public EventArgs
// класс сборщика мусора ChatEventArg: EventArgs
{
public:
String *pName;
ChatEventArg(String *pName)
{
pName = pName;
} };
Указатель на экземпляр делегата объявляется с использованием ключевого слова _event (событие).
_gc class ChatServer // класс сборщика мусора ChatServer
{
public:
_event JoinHandler *pJoin;
_event QuitHandler *pQuit;
Обычно для упрощения вызова делегатов, связанных с обработчиком некоторого события, используют вспомогательный метод. О вызове делегата часто говорят, как о "запуске" события.
_gc class ChatServer
// класс сборщика мусора ChatServer
{
protected: // защищенный
void OnJoin(ChatEventArg *pe)
{
if (pJoin != 0)
{
pJoin(this, pe); // запуск события
}
}
void OnQuit(ChatEventArg *pe)
{
if (pQuit != 0)
{
pQuitfthis, pe); // запуск события
}
}
Приведенный здесь вспомогательный метод проверяет, обрабатывается ли событие каким-либо экземпляром делегата. (Проверка проводится сравнением с 0.) Обычно такие вспомогательные методы объявляются как защищенные (protected), так что доступ к ним имеют только производные классы.
Теперь с помощью вызова вспомогательных методов можно запускать события.
_gc class ChatServer
// класс сборщика мусора ChatServer
{
public:
void JoinChat(String *pName)
{
pMembers->Add(pName); // Добавить
OnJoin(new ChatEventArg(pName));
}
void QuitChat(String *pName)
{
pMembers->Remove(pName); // Удалить
OnQuitfnew ChatEventArg(pName));
}